/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package eu.fastl.dragster.loadgen.impl;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.fastl.dragster.loadgen.UrlProvider;
import eu.fastl.dragster.util.UrlUtils;

/**
 * Simple Url Provider Implementation reading urls from a file
 *
 * @author Ernst Fastl
 */
public class FileReaderUrlProvider implements UrlProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileReaderUrlProvider.class);

    private final String fileName;
    private final int numRuns;
    private int resetCount = 0;
    private BufferedReader input;
    private FileInputStream fileInputStream;
    private final VariableSubstituter variableSubstituter = new VariableSubstituter();

    public FileReaderUrlProvider(String fileName, int numRuns) throws IOException {
        this.fileName = fileName;
        this.numRuns = numRuns;
        reset();
    }

    private void reset() throws IOException {
        close();
        this.fileInputStream = new FileInputStream(this.fileName);
        this.input = new BufferedReader(new InputStreamReader(this.fileInputStream));
        this.resetCount++;
    }

    private void close() throws IOException {
        if (this.input != null)
            this.input.close();
        if (this.fileInputStream != null)
            this.fileInputStream.close();
        this.fileInputStream = null;
        this.input = null;
    }

    public synchronized String getNextUrl() {
        if (isFinished())
            return null;
        try {
            String line = internalGetNextLine();
            if (line == null) {
                close();
                return null;
            }
            String substitutedUrl = this.variableSubstituter.substituteVariables(line);
            if (UrlUtils.isValidUrl(substitutedUrl)) {
                return substitutedUrl;
            } else {
                LOGGER.debug("Trying to encode parameters of invalid url in input file: " + substitutedUrl);
                String urlWithEncodedParameters = UrlUtils.encodeParameters(substitutedUrl);
                if (UrlUtils.isValidUrl(urlWithEncodedParameters)) {
                    LOGGER.debug("Successfully created valid URL: " + urlWithEncodedParameters);
                    return urlWithEncodedParameters;
                } else {
                    if (StringUtils.isNotBlank(substitutedUrl))
                        LOGGER.warn("INVALID URL:" + substitutedUrl);
                    return getNextUrl();
                }
            }
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    private boolean isFinished() {
        return this.input == null;
    }

    private String internalGetNextLine() throws IOException {
        String line = this.input.readLine();
        if (line == null && (this.resetCount < this.numRuns || this.numRuns == 0)) {
            reset();
            line = this.input.readLine();
        }
        return line;
    }

}
